﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Data.Common;
using System.Text.RegularExpressions;

namespace ddr3_io_csv2xdc
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        string currentFilePath;
        //统计约束数量
        static Dictionary<int, int> xdcDict = new Dictionary<int, int> { 
        {0,0},
        {1,0},
        {2,0},
        {3,0},
        {4,0},
        {5,0},
        {6,0},
        {7,0},
        {8,0},
        {9,0},
        {10,0},
        {11,0},
        {12,0},
        {13,0}
        
        };
        
       

        List<Tuple<string, string>> netPortMap = new List<Tuple<string, string>>();


        private void button1_Click(object sender, EventArgs e)
        {
            //string ddr3_io_excel_file_path = "D://LCPfiles//TASKS//23suo_highsppedAdc//23suo_high_speed_ddr3_pins.xlsx";
            int err_num = CSVFileProcess();
           if (err_num != 0)
           {
               MessageBox.Show("处理CSV文件出错！");
           }
        }
        //处理CSV文件以生成XDC文件
        //输入：CSV文件路径
        //输出：错误报告序号，XDC文件将生成在同一目录下
        public int CSVFileProcess()
        {
            
                OpenFileDialog openFile = new OpenFileDialog();
                //openFile.InitialDirectory = "D://LCPfiles//TASKS//23suo_highsppedAdc//";
                openFile.Filter = "CSV Flile(*.csv)|*.csv";
                openFile.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                openFile.Multiselect = false;
                if (openFile.ShowDialog() == DialogResult.Cancel) return -1;
                var filePath = openFile.FileName;
                currentFilePath = filePath;
                string fileType = System.IO.Path.GetExtension(filePath);
                if (string.IsNullOrEmpty(fileType)) return -2;
                FileInfo fileinfo = new FileInfo(openFile.SafeFileName);


                string configFilePath = Directory.GetCurrentDirectory() + "\\config.ini";
                Console.Write(configFilePath);

                
                netPortMap = LoadConfigFile(configFilePath);
                
                
                
                //read data from file
                DataTable dt = new DataTable();
                dt = LoadCSV(filePath);
                //重置约束数量计数
                for (int i = 0; i < 14; i++)
                {
                    xdcDict[i] = 0;
                }
                //gen xdc file
                string fileDir = System.IO.Path.GetDirectoryName(filePath);
                string fileNameNoSuffix = System.IO.Path.GetFileNameWithoutExtension(filePath);
                FileStream fs_1 = new FileStream(fileDir + "\\" + fileNameNoSuffix + ".xdc", FileMode.OpenOrCreate , FileAccess.ReadWrite);
                fs_1.Close();
                FileStream fs = new FileStream(fileDir  + "\\"+fileNameNoSuffix + ".xdc", FileMode.Truncate , FileAccess.ReadWrite);
                StreamWriter sw = new StreamWriter(fs); // 创建写入流
                
                foreach (DataRow dr in dt.Rows)
                {
                   

                    Tuple<string, string, string, int> answer;
                    answer = findNetNameInMap(dr);
                    if( answer != null)
                    {
                        string xdcLine = genXDCLine(answer.Item1.ToString(), answer.Item2.ToString(), answer.Item3.ToString(), answer.Item4, dr["chipAndPinName"].ToString());
                        sw.Write(xdcLine + "\n");
                        printMsgInLog(xdcLine + "\n");
                        xdcDict[answer.Item4] = xdcDict[answer.Item4] + 1;
                    }

                }
                sw.Close(); //关闭文件
                fs.Close();
                //统计约束数量
                printMsgInLog("============================================\n");
                printMsgInLog("生成xdc文件成功，已保存在读取的csv文件同一路径下\n");
                printMsgInLog("约束数量统计==================================\n");
                foreach (int key in xdcDict.Keys)
                { 
                    printMsgInLog(netPortMap[key].Item1 + ":    "+xdcDict[key].ToString()+"\n");
    
                }
                //MessageBox.Show("生成xdc文件成功，已保存在读取的csv文件同一路径下");


                return 0;
            
        }
       
        private void button2_Click(object sender, EventArgs e)
        {
            //listView1.Columns.Add("Net Name");
            //ListViewItem lsItem = listView1.Items.Add((listView1.Items.Count + 1) + "");
            //lsItem.SubItems.Add("kl");

           
        }

        public void printMsgInLog(string str)
        {
            log_richTextBox.Text += str;
            log_richTextBox.SelectionStart = log_richTextBox.Text.Length;
            log_richTextBox.SelectionLength = 0;
            log_richTextBox.Focus();
        }

        /// <summary>
        /// 将配置文件中的配置信息装载到每个TextBox
        /// </summary>
        /// <param name="fileName">配置文件路径</param>
        /// <returns>返回读取了配置数据的List</returns>

        public List<Tuple<string, string>> LoadConfigFile(string filePath)
        {
            

            FileStream fs = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            StreamReader sr = new StreamReader(fs, Encoding.Default);

            //记录每次读取的一行记录
            string strLine = "";
            //记录每行记录中的各字段内容
            string[] aryLine = null;
           
            List<Tuple<string, string>> netPortMap = new List<Tuple<string, string>>();

            string netName, portName;
            while ((strLine = sr.ReadLine()) != null && strLine != "" )
            {
                if (strLine != ";")
                {
                    //每行只有一个逗号
                    aryLine = strLine.Split(',');
                    netName = aryLine[0].Replace(" ", "");
                    portName = aryLine[1].Replace(" ", "");
                    Tuple<string, string> tuple_temp = new Tuple<string, string>(netName, portName);
                    netPortMap.Add(tuple_temp);
                    

                }
            }


            sr.Close();
            fs.Close();

            return netPortMap;
        }
        
        /// <summary>
        /// 将CSV文件的数据读取到DataTable中
        /// </summary>
        /// <param name="fileName">CSV文件路径</param>
        /// <returns>返回读取了CSV数据的DataTable</returns>
        public static DataTable LoadCSV(string filePath)
        {
            //Encoding encoding = System.Data.Common.GetType(filePath); //Encoding.ASCII;//
            DataTable dt = new DataTable();
            FileStream fs = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);

            //StreamReader sr = new StreamReader(fs, Encoding.UTF8);
            StreamReader sr = new StreamReader(fs, Encoding.Default);
            //string fileContent = sr.ReadToEnd();
            //encoding = sr.CurrentEncoding;
            //记录每次读取的一行记录
            string strLine = "";
            //记录每行记录中的各字段内容
            string[] aryLine = null;
            string[] tableHead = null;
            //标示列数
            int columnCount = 0;
            //标示是否是读取的第一行
            bool IsFirst = true;
            //逐行读取CSV中的数据
            DataColumn netName = new DataColumn("NetName");
            DataColumn chipAndPinName = new DataColumn("chipAndPinName");
            dt.Columns.Add(netName);
            dt.Columns.Add(chipAndPinName);
            columnCount = 2;
            while ((strLine = sr.ReadLine()) != null)
            {                
                    if(strLine.Contains(','))
                    {

                        aryLine = strLine.Split(',');
                        DataRow dr = dt.NewRow();
                        for (int j = 0; j < columnCount; j++)
                        {
                            dr[j] = aryLine[j];
                        }
                        dt.Rows.Add(dr);     
                    }
            }
           

            sr.Close();
            fs.Close();
            return dt;
        }

        private void 如何使用ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("根据config.ini文件，来让工具对输入的csv表格进行处理，导入CSV文件即可在同一路径下生成XDC文件，注意CSV文件需要有固定格式，必须分为2列，左列为网络名称（例如“DDR3_CAS_N”），右列为带有FPGA器件名称的引脚名（例如“U2.A19”）");
        }

        private void 版本信息ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("当前版本0.021，Release @ 2018-5-29，开发环境VS2012。作者：李朝鹏");
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //List<Tuple<string, string>> netPortMap = new List<Tuple<string, string>>();
            //string configFilePath = Directory.GetCurrentDirectory() + "\\config.csv";
            //netPortMap = LoadConfigFile(configFilePath);
        }
        //寻找网络名称
        private Tuple<string, string, string, int> findNetNameInMap(DataRow dr)
        {
            Tuple<string, string, string, int> answer = null;
            string netName;
            for (int index = 0; index < netPortMap.Count; index++)
            {
                netName = dr["NetName"].ToString();
                if (netName.Contains(netPortMap[index].Item1.ToString()))
                {
                    if (netName.Contains(netPortMap[13].Item1.ToString()))
                    {
                        answer = new Tuple<string, string, string, int>(netName,
                                                               netPortMap[13].Item1.ToString(),
                                                               netPortMap[13].Item2.ToString(),
                                                               13);
                    }
                    else
                    {
                        answer = new Tuple<string, string, string, int>(netName,
                                                               netPortMap[index].Item1.ToString(),
                                                               netPortMap[index].Item2.ToString(),
                                                               index);
                    }

                    return answer;

                }

                

            }
            return answer;
        
        }

        //生成XDC
        private string genXDCLine(string netName, string netNameNoIndex, string portName, int number, string originString)
        {
            string xdcLine = null;
            string[] originStringSplit = originString.Split(' ');
            string pinLOC = "";
            string fpgaName = netPortMap[14].Item2.ToString();
             
            string portNameNoSpace = portName;
            //portNameNoSpace = portNameNoSpace.Replace(" ", "");
            //避免空格引起错误
            fpgaName = fpgaName.Replace(" ", "");
            foreach (string cell in originStringSplit)
            {
                //获取FPGA引脚位置
                if (cell.Contains(fpgaName))
                    pinLOC = cell.Substring(fpgaName.Length + 1);        
            }
          
            //固定名称的引脚 
            if (number <= 8)
            {
                xdcLine = "set_property PACKAGE_PIN " + pinLOC + " [get_ports {" + portNameNoSpace + "}]";
            
            }
            //DM，DQ，ADDR， BA单端信号
            if (9 <= number && number <= 12)
            {
                string portNameIndex = netName.Substring(netNameNoIndex.Length);
                xdcLine = "set_property PACKAGE_PIN " + pinLOC + " [get_ports {" + portNameNoSpace + "[" + portNameIndex + "]}]";
            }
            //DQS，差分信号
            if (number == 13)
            {
                string portNameRes = netName.Substring(netNameNoIndex.Length);
                Regex rgx = new Regex("\\D");
                Regex rgx2 = new Regex("[^a-zA-Z]");
                string portNameIndex = rgx.Replace(portNameRes, "");
                string portNamePolarity = rgx2.Replace(portNameRes, "");
                portNamePolarity = portNamePolarity.ToLower();
                xdcLine = "set_property PACKAGE_PIN " + pinLOC + " [get_ports {" + portNameNoSpace + "_" + portNamePolarity + "[" + portNameIndex + "]}]";
            }


            return xdcLine;
        
        }

        
    }

    
        

        
    
}
